package com.lu.manage.modular.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lu.manage.core.common.constant.SystemConstant;
import com.lu.manage.core.common.node.TreeNodes;
import com.lu.manage.core.common.node.ZTreeNode;
import com.lu.manage.core.utils.ToolUtil;
import com.lu.manage.modular.system.mapper.MenuMapper;
import com.lu.manage.modular.system.model.Menu;
import com.lu.manage.modular.system.model.dto.MenuDto;
import com.lu.manage.modular.system.model.enums.MenuYesOrNo;
import com.lu.manage.modular.system.service.ConstantService;
import com.lu.manage.modular.system.service.MenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

/**
 * @program LuBoot
 * @description:
 * @author: zhanglu
 * @create: 2019-10-08 10:30:00
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    @Autowired
    private ConstantService constantService;

    @Override
    public List<String> findPermissionsByRoleId(String roleId) {
        return this.baseMapper.findPermissionsByRoleId(roleId);
    }

    @Override
    public List<TreeNodes> getMenusByRolesIds(List<String> roleList) {
        List<TreeNodes> menus = this.baseMapper.getMenusByRoleIds(roleList);
//        //给所有菜单url加上ctxPath
//        for (TreeNodes menu : menus) {
//
//        }

        return menus;
    }

    @Override
    public List<Map<String, Object>> selectMenuTree(String searchWords, String level) {
        List<Map<String, Object>> menus = this.baseMapper.selectMenuTree(searchWords, level);
        return menus;
    }

    @Override
    public List<ZTreeNode> menuTreeList() {
        return this.baseMapper.menuTreeList();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public MenuDto add(MenuDto menuDto) throws Exception {

        //判断值不空
        if (ToolUtil.isOneEmpty(menuDto, menuDto.getCode(), menuDto.getName(), menuDto.getPid(), menuDto.getMenuFlag(), menuDto.getUrl())) {
            throw new Exception("请求数据不完整或格式错误!");
        }

        //如果编号和父编号一致，遍历菜单树的时候会导致无限递归
        if(menuDto.getCode().equals(menuDto.getPcode())){
            throw new Exception("菜单编号和父亲编号不能一致!");
        }

        //判断是否已经存在该编号
        String existedMenuName = constantService.getMenuNameByCode(menuDto.getCode());
        if (ToolUtil.isNotEmpty(existedMenuName)) {
            throw new Exception("菜单编号重复，不能添加");
        }

        //组装属性，设置父级菜单编号
        Menu menu = this.menuSetPcode(menuDto);
        menu.setStatus(MenuYesOrNo.YES.getCode());
        this.save(menu);

        menuDto.setMenuId(menu.getMenuId());
        return menuDto;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void update(MenuDto menuDto) throws Exception {

        //判断值不空
        if (ToolUtil.isOneEmpty(menuDto, menuDto.getCode(), menuDto.getName(), menuDto.getPid(), menuDto.getMenuFlag(), menuDto.getUrl())) {
            throw new Exception("请求数据不完整或格式错误!");
        }

        //获取旧的菜单
        String id = menuDto.getMenuId();
        Menu menu = this.getById(id);
        if(ToolUtil.isEmpty(menuDto)){
            throw new Exception("请求数据不完整或格式错误!");
        }

        //设置父级菜单编号
        Menu resMenu = this.menuSetPcode(menuDto);

        //查找该节点的子集合,并修改相应的pcode和level(因为菜单修改后,层级可能也变化了)
        updateSubMenuLevels(menu, resMenu);

        this.updateById(resMenu);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteMenuSubMenus(String menuId) throws Exception {

        Menu menu = this.getById(menuId);

        //删除当前菜单
        deleteMenu(menuId);

        //删除当前菜单下的所有子菜单
        List<Menu> menus = this.baseMapper.getMenusLikePcodes(menu.getCode());

        for (Menu temp : menus) {
            deleteMenu(temp.getMenuId());
        }
    }

    @Override
    public void sortAllMenus(String nodes) throws Exception {
        List<TreeNodes> nodeList = JSONArray.parseArray(nodes, TreeNodes.class);
        for (TreeNodes node : nodeList) {
            handle(0, node);
        }
    }

    @Override
    public List<String> getMenuIdsByRoleId(String roleId) throws Exception {
        return this.baseMapper.getMenuIdsByRoleId(roleId);
    }

    @Override
    public List<ZTreeNode> menuTreeListByMenuIds(List<String> menuIds) throws Exception {
        return this.baseMapper.menuTreeListByMenuIds(menuIds);
    }

    public void handle(int index, TreeNodes treeNodes){
        int count = 0;
        for (TreeNodes m : treeNodes.getChildren()) {
            count++;
            if(ToolUtil.isEmpty(m.getChildren())){
                Menu menu = new Menu();
                menu.setMenuId(m.getId());
                menu.setSort(count);
                System.out.println(menu.toString());
                this.baseMapper.updateById(menu);
            }else {
                index++;
                handle(index, m);
                Menu menu = new Menu();
                menu.setMenuId(m.getId());
                menu.setSort(index);
                System.out.println(menu.toString());
                this.baseMapper.updateById(menu);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteMenu(String menuId) {

        //删除菜单
        this.baseMapper.deleteById(menuId);

        //删除关联的relation
        this.baseMapper.deleteRelationByMenu(menuId);
    }

    /**
     * 更改所有子菜单的结构
     * @param oldMenu
     * @param newMenu
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateSubMenuLevels(Menu oldMenu, Menu newMenu) {
        List<Menu> menus = this.baseMapper.getMenusLikePcodes(oldMenu.getCode());

        for (Menu menu : menus) {
            //更新pcode
            if(oldMenu.getCode().equals(menu.getPcode())){
                menu.setPcode(newMenu.getCode());
            }

            //更新pcodes
            String oldPcodesPrefix = oldMenu.getPcodes() + "[" + oldMenu.getCode() + "],";
            String oldPcodesSuffix = menu.getPcodes().substring(oldPcodesPrefix.length());
            String menuPcodes = newMenu.getPcodes() + "[" + newMenu.getCode() + "]," + oldPcodesSuffix;
            menu.setPcodes(menuPcodes);

            //更新levels
            int level = StrUtil.count(menuPcodes, "[");
            menu.setLevels(level);

            this.updateById(menu);
        }

    }

    /**
     * 转化请求的数据：
     *  - 通过选择的父级id，设置自己的pcode、pcodes、levels
     * @param menuDto
     * @return
     */
    private Menu menuSetPcode(MenuDto menuDto) {

        Menu resMenu = new Menu();
        BeanUtil.copyProperties(menuDto, resMenu);

        if(ToolUtil.isEmpty(menuDto.getPid()) || menuDto.getPid().equals(SystemConstant.pid)){
            resMenu.setPcode(SystemConstant.pid);
            resMenu.setLevels(SystemConstant.pLevels);
            resMenu.setPcodes("[" + SystemConstant.pid + "],");
        }else {
            Menu pMenu = this.getById(menuDto.getPid());
            Integer pLevels = pMenu.getLevels();
            resMenu.setPcode(pMenu.getCode());
            resMenu.setLevels(pLevels + 1);
            resMenu.setPcodes(pMenu.getPcodes() + "[" + pMenu.getCode() + "],");
        }

        return resMenu;
    }

}
